package in.co.codedoc.cg;

import in.co.codedoc.cg.annotations.BooleanType;
import in.co.codedoc.cg.annotations.ByteType;
import in.co.codedoc.cg.annotations.CharType;
import in.co.codedoc.cg.annotations.DoubleType;
import in.co.codedoc.cg.annotations.FloatType;
import in.co.codedoc.cg.annotations.IntType;
import in.co.codedoc.cg.annotations.LongType;
import in.co.codedoc.cg.annotations.ShortType;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;

public class TypeUtil
{
	public static String GetReferenceType(String typeName)
	{
		if(typeName.equals("byte"))
		{
			return "Byte";
		}
		else if(typeName.equals("boolean"))
		{
			return "Boolean";
		}
		else if(typeName.equals("char"))
		{
			return "Character";
		}
		else if(typeName.equals("short"))
		{
			return "Short";
		}
		else if(typeName.equals("int"))
		{
			return "Integer";
		}
		else if(typeName.equals("long"))
		{
			return "Long";
		}
		else if(typeName.equals("float"))
		{
			return "Float";
		}
		else if(typeName.equals("double"))
		{
			return "Double";
		}
		else
		{
			return typeName;
		}
	}
	public static String GetTypeName(String qualName)
	{
		qualName = MapType(qualName);
		
		int firstLT = qualName.indexOf('<');

		int dotIndex = firstLT >= 0 ? qualName.lastIndexOf('.',firstLT-1) : qualName.lastIndexOf('.');
		
		return dotIndex >= 0 ? qualName.substring(dotIndex + 1) : qualName;
	}
	
	private static String MapType(String qualName)
	{
		return coreTypeByClass.containsKey(qualName) ? coreTypeByClass.get(qualName) : qualName;
	}

	public static String GetImportStatement(String qualName)
	{
		if(coreTypes.contains(GetTypeName(qualName)))
		{
			return "";
		}
		
		qualName = CleanupSyntaxElements(qualName);
		
		int lastDotIndex = qualName.lastIndexOf('.');
		
		return lastDotIndex >= 0 ? ("import " + qualName.substring(0,lastDotIndex) + ".*;") : "";
	}
	
	private static String CleanupSyntaxElements(String qualName)
	{
		int firstLT = qualName.indexOf('<');
		int arrayIndex = qualName.indexOf("[]");
		if(firstLT > 0)
		{
			return qualName.substring(0,firstLT);
		}
		else if(arrayIndex > 0)
		{
			return qualName.substring(0,arrayIndex);
		}
		else
		{
			return qualName;
		}
	}
	
	public static boolean IsPrimitiveType(String typeName)
	{
		return primitiveTypes.contains(typeName);
	}

	@SuppressWarnings("unchecked")
	public static Class GetPrimitiveType(String typeName)
	{
		typeName = "java.lang." + GetReferenceType(typeName);
		
		try
		{
			Class type = Class.forName(typeName);
			
			Field field = type.getField("TYPE");
			
			return (Class) field.get(null);
		}
		catch(Throwable th)
		{
			throw new RuntimeException(th);
		}
	}
	
	@SuppressWarnings("unchecked")
	public static Class GetPrimitiveTypeRepresentative(String typeName)
	{
		return primitiveTypeRepresentativeByName.get(typeName);
	}

	private static HashMap<String,String> coreTypeByClass = new HashMap<String,String>();
	static
	{
		coreTypeByClass.put(ByteType.class.getCanonicalName(),"byte");
		coreTypeByClass.put(CharType.class.getCanonicalName(),"char");
		coreTypeByClass.put(ShortType.class.getCanonicalName(),"short");
		coreTypeByClass.put(IntType.class.getCanonicalName(),"int");
		coreTypeByClass.put(LongType.class.getCanonicalName(),"long");
		coreTypeByClass.put(BooleanType.class.getCanonicalName(),"boolean");
		coreTypeByClass.put(FloatType.class.getCanonicalName(),"float");
		coreTypeByClass.put(DoubleType.class.getCanonicalName(),"double");
	}
	
	private static HashSet<String> coreTypes = new HashSet<String>();
	static
	{
		coreTypes.add("String");
		coreTypes.add("byte");
		coreTypes.add("char");
		coreTypes.add("short");
		coreTypes.add("int");
		coreTypes.add("long");
		coreTypes.add("boolean");
		coreTypes.add("float");
		coreTypes.add("double");
		coreTypes.add("Byte");
		coreTypes.add("Character");
		coreTypes.add("Short");
		coreTypes.add("Integer");
		coreTypes.add("Long");
		coreTypes.add("Float");
		coreTypes.add("Double");
		coreTypes.add("IdSetId");
		coreTypes.add("IdListId");
	}

	private static HashSet<String> primitiveTypes = new HashSet<String>();
	static
	{
		primitiveTypes.add("byte");
		primitiveTypes.add("char");
		primitiveTypes.add("short");
		primitiveTypes.add("int");
		primitiveTypes.add("long");
		primitiveTypes.add("boolean");
		primitiveTypes.add("float");
		primitiveTypes.add("double");
	}
	
	@SuppressWarnings("unchecked")
	private static HashMap<String,Class> primitiveTypeRepresentativeByName
		= new HashMap<String, Class>();
	static
	{
		primitiveTypeRepresentativeByName.put("byte",ByteType.class);
		primitiveTypeRepresentativeByName.put("char",CharType.class);
		primitiveTypeRepresentativeByName.put("short",ShortType.class);
		primitiveTypeRepresentativeByName.put("int",IntType.class);
		primitiveTypeRepresentativeByName.put("long",LongType.class);
		primitiveTypeRepresentativeByName.put("boolean",Boolean.class);
		primitiveTypeRepresentativeByName.put("float",FloatType.class);
		primitiveTypeRepresentativeByName.put("double",DoubleType.class);
	}
	
}
